home *** CD-ROM | disk | FTP | other *** search
/ SGI Developer Toolbox 6.1 / SGI Developer Toolbox 6.1 - Disc 4.iso / public / fax / src / recvfax / main.c < prev    next >
C/C++ Source or Header  |  1994-08-01  |  9KB  |  343 lines

  1. /*    $Header: /usr/people/sam/fax/recvfax/RCS/main.c,v 1.44 1994/02/28 14:21:56 sam Rel $
  2. /*
  3.  * Copyright (c) 1990, 1991, 1992, 1993, 1994 Sam Leffler
  4.  * Copyright (c) 1991, 1992, 1993, 1994 Silicon Graphics, Inc.
  5.  *
  6.  * Permission to use, copy, modify, distribute, and sell this software and 
  7.  * its documentation for any purpose is hereby granted without fee, provided
  8.  * that (i) the above copyright notices and this permission notice appear in
  9.  * all copies of the software and related documentation, and (ii) the names of
  10.  * Sam Leffler and Silicon Graphics may not be used in any advertising or
  11.  * publicity relating to the software without the specific, prior written
  12.  * permission of Sam Leffler and Silicon Graphics.
  13.  * 
  14.  * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, 
  15.  * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY 
  16.  * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.  
  17.  * 
  18.  * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
  19.  * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
  20.  * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
  21.  * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF 
  22.  * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE 
  23.  * OF THIS SOFTWARE.
  24.  */
  25. #include "defs.h"
  26.  
  27. #include <unistd.h>
  28. #include <fcntl.h>
  29. #include <sys/file.h>
  30. #include <sys/socket.h>
  31. #include <sys/stat.h>
  32.  
  33. char*    SPOOLDIR = FAX_SPOOLDIR;
  34.  
  35. char**    dataFiles;
  36. int*    fileTypes;
  37. int    nDataFiles = 0;
  38. int    nPollIDs = 0;
  39. char**    pollIDs;
  40. char    line[1024];        /* current input line */
  41. char*    tag;            /* keyword: tag */
  42. int    debug = 0;
  43. Job*    jobList = 0;
  44. int    seqnum = 0;
  45. int    version = 0;
  46. char    userID[1024];
  47. struct    tm now;            /* current time of day */
  48.  
  49. void
  50. done(int status, char* how)
  51. {
  52.     fflush(stdout);
  53.     if (debug)
  54.     syslog(LOG_DEBUG, how);
  55.     exit(status);
  56. }
  57.  
  58. static void
  59. setUserID(const char* modemname, char* tag)
  60. {
  61.     strncpy(userID, tag, sizeof (userID)-1);
  62. }
  63.  
  64. static void
  65. setProtoVersion(const char* modemname, char* tag)
  66. {
  67.     version = atoi(tag);
  68.     if (version > FAX_PROTOVERS) {
  69.     protocolBotch(
  70.         "protocol version %u requested: only understand up to %u.",
  71.         version, FAX_PROTOVERS);
  72.     done(1, "EXIT");
  73.     }
  74. }
  75.  
  76. static void
  77. ackPermission(const char* modemname, char* tag)
  78. {
  79.     sendClient("permission", "%s", "granted");
  80.     fflush(stdout);
  81. }
  82.  
  83. #define    TRUE    1
  84. #define    FALSE    0
  85.  
  86. struct {
  87.     const char* cmd;        /* command to match */
  88.     int        check;        /* if true, checkPermission first */
  89.     void    (*cmdFunc)(const char*, char*);
  90. } cmds[] = {
  91.     { "begin",        TRUE,    submitJob },
  92.     { "checkPerm",    TRUE,    ackPermission },
  93.     { "tiff",        TRUE,    getTIFFData },
  94.     { "postscript",    TRUE,    getPostScriptData },
  95.     { "data",        TRUE,    getDataOldWay },
  96.     { "poll",        TRUE,    newPollID },
  97.     { "userID",        FALSE,    setUserID },
  98.     { "version",    FALSE,    setProtoVersion },
  99.     { "serverStatus",    FALSE,    sendServerStatus },
  100.     { "allStatus",    FALSE,    sendAllStatus },
  101.     { "userStatus",    FALSE,    sendUserStatus },
  102.     { "jobStatus",    FALSE,    sendJobStatus },
  103.     { "recvStatus",    FALSE,    sendRecvStatus },
  104.     { "remove",        TRUE,    removeJob },
  105.     { "kill",        TRUE,    killJob },
  106.     { "alterTTS",    TRUE,    alterJobTTS },
  107.     { "alterKillTime",    TRUE,    alterJobKillTime },
  108.     { "alterMaxDials",    TRUE,    alterJobMaxDials },
  109.     { "alterNotify",    TRUE,    alterJobNotification },
  110. };
  111. #define    NCMDS    (sizeof (cmds) / sizeof (cmds[0]))
  112.  
  113. main(int argc, char** argv)
  114. {
  115.     extern char* optarg;
  116.     char modemname[80];
  117.     time_t t = time(0);
  118.     int c;
  119.  
  120.     now = *localtime(&t);
  121.     openlog(argv[0], LOG_PID, LOG_FAX);
  122.     umask(077);
  123.     while ((c = getopt(argc, argv, "q:d")) != -1)
  124.     switch (c) {
  125.     case 'q':
  126.         SPOOLDIR = optarg;
  127.         break;
  128.     case 'd':
  129.         debug = 1;
  130.         syslog(LOG_DEBUG, "BEGIN");
  131.         break;
  132.     case '?':
  133.         syslog(LOG_ERR,
  134.         "Bad option `%c'; usage: faxd.recv [-q queue-dir] [-d]", c);
  135.         done(-1, "EXIT");
  136.     }
  137.     if (chdir(SPOOLDIR) < 0) {
  138.     syslog(LOG_ERR, "%s: chdir: %m", SPOOLDIR);
  139.     sendError("Can not change to spooling directory.");
  140.     done(-1, "EXIT");
  141.     }
  142.     if (debug) {
  143.     char buf[82];
  144.     syslog(LOG_DEBUG, "chdir to %s", getcwd(buf, 80));
  145.     }
  146. #if defined(SO_LINGER) && !defined(__linux__)
  147.     { struct linger opt;
  148.       opt.l_onoff = 1;
  149.       opt.l_linger = 60;
  150.       if (setsockopt(0, SOL_SOCKET, SO_LINGER, (char*)&opt, sizeof (opt)) < 0)
  151.     syslog(LOG_WARNING, "setsockopt (SO_LINGER): %m");
  152.     }
  153. #endif
  154.     strcpy(modemname, MODEM_ANY);
  155.     strcpy(userID, "");
  156.     while (getCommandLine() && !isCmd(".")) {
  157.     if (isCmd("modem")) {            /* select outgoing device */
  158.         int l = strlen(DEV_PREFIX);
  159.         char* cp;
  160.         /*
  161.          * Convert modem name to identifier form by stripping
  162.          * any leading device pathname prefix and by replacing
  163.          * '/'s with '_'s for SVR4 where terminal devices are
  164.          * in subdirectories.
  165.          */
  166.         if (strncmp(tag, DEV_PREFIX, l) == 0)
  167.         tag += l;
  168.         for (cp = tag; cp = strchr(cp, '/'); *cp = '_')
  169.         ;
  170.         strncpy(modemname, tag, sizeof (modemname)-1);
  171.     } else {
  172.         int i;
  173.         for (i = 0; i < NCMDS && !isCmd(cmds[i].cmd); i++)
  174.         ;
  175.         if (i == NCMDS) {
  176.         protocolBotch("unrecognized cmd \"%s\".", line);
  177.         done(1, "EXIT");
  178.         }
  179.         if (cmds[i].check)
  180.         checkPermission();
  181.         (*cmds[i].cmdFunc)(modemname, tag);
  182.     }
  183.     }
  184.     /* remove original files -- only links remain */
  185.     { int i;
  186.       for (i = 0; i <nDataFiles; i++)
  187.     unlink(dataFiles[i]);
  188.     }
  189.     done(0, "END");
  190. }
  191.  
  192. int
  193. getCommandLine()
  194. {
  195.     char* cp;
  196.  
  197.     if (!fgets(line, sizeof (line) - 1, stdin)) {
  198.     protocolBotch("unexpected EOF.");
  199.     return (0);
  200.     }
  201.     cp = strchr(line, '\0');
  202.     if (cp > line && cp[-1] == '\n')
  203.     *--cp = '\0';
  204.     if (cp > line && cp[-1] == '\r')        /* for telnet users */
  205.     *--cp = '\0';
  206.     if (debug)
  207.     syslog(LOG_DEBUG, "line \"%s\"", line);
  208.     if (strcmp(line, ".") && strcmp(line, "..")) {
  209.     tag = strchr(line, ':');
  210.     if (!tag) {
  211.         protocolBotch("malformed line \"%s\".", line);
  212.         return (0);
  213.     }
  214.     *tag++ = '\0';
  215.     while (isspace(*tag))
  216.         tag++;
  217.     }
  218.     return (1);
  219. }
  220.  
  221. /*
  222.  * Notify server of job parameter alteration.
  223.  */
  224. int
  225. notifyServer(const char* modem, const char* va_alist, ...)
  226. #define    fmt va_alist
  227. {
  228.     char fifoname[1024];
  229.     int fifo;
  230.  
  231.     if (strcmp(modem, MODEM_ANY) == 0)
  232.     strcpy(fifoname, FAX_FIFO);
  233.     else
  234.     sprintf(fifoname, "%s.%.*s", FAX_FIFO,
  235.         sizeof (fifoname) - (sizeof (FAX_FIFO)+2), modem);
  236.     if (debug)
  237.     syslog(LOG_DEBUG, "notify server for \"%s\"", modem);
  238.     fifo = open(fifoname, O_WRONLY|O_NDELAY);
  239.     if (fifo != -1) {
  240.     char buf[2048];
  241.     int len, ok;
  242.     va_list ap;
  243.  
  244.     va_start(ap, fmt);
  245.     vsprintf(buf, fmt, ap);
  246.     va_end(ap);
  247.     len = strlen(buf);
  248.     if (debug)
  249.         syslog(LOG_DEBUG, "write \"%.*s\" to fifo", len, buf);
  250.     /*
  251.      * Turn off O_NDELAY so that write will block if FIFO is full.
  252.      */
  253.     if (fcntl(fifo, F_SETFL, fcntl(fifo, F_GETFL, 0) &~ O_NDELAY) <0)
  254.         syslog(LOG_ERR, "fcntl: %m");
  255.     ok = (write(fifo, buf, len+1) == len+1);
  256.     if (!ok)
  257.         syslog(LOG_ERR, "FIFO write failed: %m");
  258.     close(fifo);
  259.     return (ok);
  260.     } else if (debug)
  261.     syslog(LOG_INFO, "%s: Can not open for notification: %m", fifoname);
  262.     return (0);
  263. }
  264. #undef fmt
  265.  
  266. extern int parseAtSyntax(const char*, const struct tm*, struct tm*, char* emsg);
  267.  
  268. int
  269. cvtTime(const char* spec, struct tm* ref, u_long* result, const char* what)
  270. {
  271.     char emsg[1024];
  272.     struct tm when;
  273.     if (!parseAtSyntax(spec, ref, &when, emsg)) {
  274.     sendAndLogError("Error parsing %s \"%s\": %s.", what, spec, emsg);
  275.     return (0);
  276.     } else {
  277.     *result = (u_long) mktime(&when);
  278.     return (1);
  279.     }
  280. }
  281.  
  282. void
  283. vsendClient(char* tag, char* fmt, va_list ap)
  284. {
  285.     fprintf(stdout, "%s:", tag);
  286.     vfprintf(stdout, fmt, ap);
  287.     fputc('\n', stdout);
  288.     if (debug) {
  289.     char buf[2048];
  290.     sprintf(buf, "%s:", tag);
  291.     vsprintf(buf+strlen(buf), fmt, ap);
  292.     syslog(LOG_DEBUG, "%s", buf);
  293.     }
  294. }
  295.  
  296. void
  297. sendClient(char* tag, char* va_alist, ...)
  298. #define    fmt va_alist
  299. {
  300.     va_list ap;
  301.     va_start(ap, fmt);
  302.     vsendClient(tag, fmt, ap);
  303.     va_end(ap);
  304. }
  305. #undef fmt
  306.  
  307. void
  308. sendError(char* va_alist, ...)
  309. #define    fmt va_alist
  310. {
  311.     va_list ap;
  312.     va_start(ap, fmt);
  313.     vsendClient("error", fmt, ap);
  314.     va_end(ap);
  315. }
  316. #undef fmt
  317.  
  318. void
  319. sendAndLogError(char* va_alist, ...)
  320. #define    fmt va_alist
  321. {
  322.     va_list ap;
  323.     va_start(ap, fmt);
  324.     vsendClient("error", fmt, ap);
  325.     vsyslog(LOG_ERR, fmt, ap);
  326.     va_end(ap);
  327. }
  328. #undef fmt
  329.  
  330. void
  331. protocolBotch(char* va_alist, ...)
  332. #define    fmt va_alist
  333. {
  334.     char buf[1024];
  335.     va_list ap;
  336.     va_start(ap, fmt);
  337.     sprintf(buf, "Protocol botch, %s", fmt);
  338.     vsendClient("error", buf, ap);
  339.     vsyslog(LOG_ERR, buf, ap);
  340.     va_end(ap);
  341. }
  342. #undef fmt
  343.